package com.raise.drive.model.search;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
import java.io.Serializable;

/**
 * Author: Evgeny Morozov
 */
public class SearchRequest implements Serializable {

	private static final long serialVersionUID = 1L;

	public static final int DEFAULT_PAGE = 1;
	public static final int DEFAULT_LIMIT = 30;
	public static final String DEFAULT_SORTED_FIELD = "id";
	public static final int SEARCH_AND = 0;
	public static final int SEARCH_OR = 1;

	private int page;

	private int limit;

	private String sortedField;

	private boolean desc;

	private int type;

	private Map<String, String> likeSearchMap = new HashMap<String, String>();

	private Map<String, Object> equalsSearchMap = new HashMap<String, Object>();

	private Map<String, Object> notEqualsSearchMap = new HashMap<String, Object>();

	private String[] eagerPaths;

	private List<String> nullFields = new LinkedList<String>();

	private List<String> notNullFields = new LinkedList<String>();

	/**
	 * Creates default instance.
	 *
	 */
	public SearchRequest() {
		page = DEFAULT_PAGE;
		type = SEARCH_AND;
		limit = DEFAULT_LIMIT;
		sortedField = DEFAULT_SORTED_FIELD;
	}

	/**
	 * Creates an instance with the page number, the field to sort results by
	 * and the order of the results.
	 *
	 * @param page
	 *            number of the page to fetch data from.
	 * @param sortedField
	 *            field to sort result by
	 * @param desc
	 *            the order of the results
	 */
	public SearchRequest(int page, String sortedField, boolean desc) {
		this();
		this.page = page;
		this.sortedField = sortedField;
		this.desc = desc;
	}

	/**
	 * Gets the number of the page to retrieve data from.
	 *
	 * @return the number of the page to retrieve data from
	 */
	public int getPage() {
		return page;
	}

	/**
	 * Puts the number of the page to retrieve data from.
	 *
	 * @param page
	 *            the number of the page to retrieve data from
	 */
	public void setPage(int page) {
		this.page = page;
	}

	/**
	 * Gets the limit of records to obtain from database.
	 *
	 * @return limit of records to obtain from database
	 */
	public int getLimit() {
		return limit;
	}

	/**
	 * Sets limit of records to obtain from database.
	 *
	 * @param limit
	 *            limit of records to obtain from database
	 */
	public void setLimit(int limit) {
		this.limit = limit;
	}

	/**
	 * Gets the field to sort fetch results from db.
	 *
	 * @return the field to sort fetch results from db
	 */
	public String getSortedField() {
		return sortedField;
	}

	/**
	 * Sets the field to sort fetch results from db.
	 *
	 * @param sortedField
	 *            the field to sort fetch results from db
	 */
	public void setSortedField(String sortedField) {
		this.sortedField = sortedField;
	}

	/**
	 * Gets the order of the retrieved data.
	 *
	 * @return <tt>true</tt> if the records are retrieved in descending order
	 */
	public boolean isDesc() {
		return desc;
	}

	/**
	 * Sets the order of the retrieved data.
	 *
	 * @param desc
	 *            set <tt>true</tt> if you want the records to be retrieved in
	 *            descending order
	 */
	public void setDesc(boolean desc) {
		this.desc = desc;
	}

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}

	public int getStart() {
		int start = limit * (page - 1);
		return start < 0 ? 0 : start;
	}

	/**
	 * Gets the field names which should initialize while fetching the object
	 * from database.
	 *
	 * @return the field names which should initialize while fetching the object
	 *         from database
	 */
	public String[] getEagerPaths() {
		return eagerPaths;
	}

	/**
	 * Puts the field names which should initialize while fetching the object
	 * from database.
	 *
	 * @param eagerPaths -
	 *            the field names which should initialize while fetching the
	 *            object from database
	 */
	public void setEagerPaths(String[] eagerPaths) {
		this.eagerPaths = eagerPaths;
	}

	/**
	 * Gets fields and their values to find entity by. LIKE operation is used to
	 * find the entity.
	 *
	 * @return fields and their values to find entity by
	 */
	public Map<String, String> getLikeSearchMap() {
		return likeSearchMap;
	}

	/**
	 * Puts fields and their values to find entity by. LIKE operation is used to
	 * find the entity.
	 *
	 * @param likeSearchMap -
	 *            map of the fields and their values to find entity by
	 */
	public void setLikeSearchMap(Map<String, String> likeSearchMap) {
		this.likeSearchMap = likeSearchMap;
	}

	/**
	 * Gets fields and their values to find entity by. = operation is used to
	 * find the entity.
	 *
	 * @return fields and their values to find entity by. = operation is used to
	 *         find the entity
	 */
	public Map<String, Object> getEqualsSearchMap() {
		return equalsSearchMap;
	}

	/**
	 * Puts fields and their values to find entity by. = operation is used to
	 * find the entity.
	 *
	 * @param equalsSearchMap -
	 *            fields and their values to find entity by
	 */
	public void setEqualsSearchMap(Map<String, Object> equalsSearchMap) {
		this.equalsSearchMap = equalsSearchMap;
	}

	public void addLikeCriteria(String fieldName, String value) {
		likeSearchMap.put(fieldName, value);
	}

	/**
	 * Adds a pair of equal field name-value.
	 *
	 * @param fieldName
	 *            name of the field to add the criteria to
	 * @param value
	 *            value of the field to add to the equal criteria collection
	 */
	public void addEqalCriteria(String fieldName, Object value) {
		equalsSearchMap.put(fieldName, value);
	}

	/**
	 * Gets the list of fields that should be null.
	 *
	 * @return list of fields that should be null
	 */
	public List<String> getNullFields() {
		return nullFields;
	}

	/**
	 * Sets list of fields that should be null.
	 *
	 * @param nullFields
	 *            list of fields that should be null
	 */
	public void setNullFields(List<String> nullFields) {
		this.nullFields = nullFields;
	}

	/**
	 * Gets the map of fields that should not be equal to their values.
	 *
	 * @return map of fields that should not be equal to their values
	 */
	public Map<String, Object> getNotEqualsSearchMap() {
		return notEqualsSearchMap;
	}

	/**
	 * Sets map of fields that should not be equal to their values.
	 *
	 * @param notEqualsSearchMap
	 *            map of fields that should not be equal to their values
	 */
	public void setNotEqualsSearchMap(Map<String, Object> notEqualsSearchMap) {
		this.notEqualsSearchMap = notEqualsSearchMap;
	}

	/**
	 * Gets the list of fields that should be not null.
	 *
	 * @return list of fields that should be not null
	 */
	public List<String> getNotNullFields() {
		return notNullFields;
	}

	/**
	 * Sets list of fields that should be not null.
	 *
	 * @param notNullFields
	 *            list of fields that should be not null
	 */
	public void setNotNullFields(List<String> notNullFields) {
		this.notNullFields = notNullFields;
	}
}
